package cn.iocoder.yudao.module.wecom.service.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.*;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.yudao.module.system.api.tenant.TenantApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserSaveReqDTO;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.wecom.controller.admin.user.vo.WeComQuickLoginReqVo;
import cn.iocoder.yudao.module.wecom.dal.dataobject.apiconfig.WeComApiConfigDO;
import cn.iocoder.yudao.module.wecom.dal.dataobject.providerconfig.WeComProviderConfigDO;
import cn.iocoder.yudao.module.wecom.http.WeApi;
import cn.iocoder.yudao.module.wecom.service.apiconfig.WeComApiConfigService;
import cn.iocoder.yudao.module.wecom.service.providerconfig.WeComProviderConfigService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import cn.iocoder.yudao.module.wecom.controller.admin.user.vo.*;
import cn.iocoder.yudao.module.wecom.dal.dataobject.user.WeUserDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.wecom.dal.mysql.user.WeUserMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.wecom.enums.ErrorCodeConstants.*;

/**
 * 企微员工 Service 实现类
 *
 * @author 数创万维
 */
@Service
@Validated
@Slf4j
public class WeUserServiceImpl implements WeUserService {

    @Resource
    private WeUserMapper weUserMapper;

    @Resource
    private WeComApiConfigService apiConfigService;

    @Resource
    private WeComProviderConfigService providerConfigService;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private OAuth2TokenApi oAuth2TokenApi;

    @Resource
    private TenantApi tenantApi;

    @Resource
    private ConfigApi configApi;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private final static String LOCK_KEY = "QW_SYNC_LOCK:";

    private final static String USER_BIND_KEY = "user_bind_key:";

    //加了dev1
    private final static String USER_AUTH_REDIRECT_URL = "https://scrm.jzsaas.com/open-api/wecom/user/auth/callback";

    @Override
    public Long createWeUser(WeUserSaveReqVO createReqVO) {
        // 插入
        WeUserDO weUser = BeanUtils.toBean(createReqVO, WeUserDO.class);
        weUserMapper.insert(weUser);
        // 返回
        return weUser.getId();
    }

    @Override
    public void updateWeUser(WeUserSaveReqVO updateReqVO) {
        // 校验存在
//        validateWeUserExists(updateReqVO.getId());
        // 更新
        WeUserDO updateObj = BeanUtils.toBean(updateReqVO, WeUserDO.class);
        weUserMapper.updateById(updateObj);
    }

    @Override
    public void deleteWeUser(Long id) {
        // 校验存在
//        validateWeUserExists(id);
        // 删除
        weUserMapper.deleteById(id);
    }

//    private void validateWeUserExists(Long id) {
//        if (weUserMapper.selectById(id) == null) {
//            throw exception(WE_USER_NOT_EXISTS);
//        }
//    }

    @Override
    public WeUserDO getWeUser(Long id) {
        return weUserMapper.selectById(id);
    }

    @Override
    public PageResult<WeUserDO> getWeUserPage(WeUserPageReqVO pageReqVO) {
        return weUserMapper.selectPage(pageReqVO);
    }


    @Override
    public void createEventHandle(Map<String, Object> allFieldsMap) {
        String UserId = allFieldsMap.get("UserID").toString();
        String Name = allFieldsMap.get("Name").toString();
        String Department = allFieldsMap.get("Department").toString();
        String Gender = allFieldsMap.get("Gender").toString();
        String Email = allFieldsMap.get("Email").toString();
        String Avatar = allFieldsMap.get("Avatar").toString();
        String Mobile = allFieldsMap.get("Mobile").toString();
        String Status = allFieldsMap.get("Status").toString();
        WeUserDO user = weUserMapper.selectOne(WeUserDO::getWeUserId, UserId);
        if (Objects.isNull(user)) {
            user = new WeUserDO();
            user.setWeUserId(UserId);
            user.setNickname(Name);
            user.setDeptId("," + StrUtil.replace(Department, "[", "").replace("]", "") + ",");
            user.setGender(Integer.parseInt(Gender));
            user.setEmail(Email);
            user.setAvatar(Avatar);
            user.setTelephone(Mobile);
            user.setStatus(Integer.parseInt(Status));
            user.setBindStatus(0);
            weUserMapper.insert(user);
        }

    }

    @Override
    public void updateEventHandle(Map<String, Object> allFieldsMap) {
        String UserId = allFieldsMap.get("UserID").toString();
        String NewUserId = allFieldsMap.get("NewUserId").toString();
        String Name = allFieldsMap.get("Name").toString();
        String Department = allFieldsMap.get("Department").toString();
        String Gender = allFieldsMap.get("Gender").toString();
        String Email = allFieldsMap.get("Email").toString();
        String Avatar = allFieldsMap.get("Avatar").toString();
        String Mobile = allFieldsMap.get("Mobile").toString();
        String Status = allFieldsMap.get("Status").toString();
        WeUserDO user = weUserMapper.selectOne(WeUserDO::getWeUserId, UserId);
        if (Objects.nonNull(user)) {
            user.setWeUserId(NewUserId);
            user.setNickname(Name);
            user.setDeptId("," + StrUtil.replace(Department, "[", "").replace("]", "") + ",");
            user.setGender(Integer.parseInt(Gender));
            user.setEmail(Email);
            user.setAvatar(Avatar);
            user.setTelephone(Mobile);
            user.setStatus(Integer.parseInt(Status));
            weUserMapper.updateById(user);
        }
    }

    @Override
    public void resetUserNameEventHandle(Map<String, Object> allFieldsMap) {

        // TODO: 重置了用户登录账号？ 这个事件看仔细了在开发吧
    }

    @Override
    public void deleteUserEventHandle(Map<String, Object> allFieldsMap) {

        // TODO: 只需要处理删除与crm 账号的绑定关系即可； ======
        String UserId = allFieldsMap.get("UserID").toString();
        weUserMapper.delete(WeUserDO::getWeUserId, UserId);

    }

    @Override
    public WeUserRespVO getBindUser() {
        WeUserDO user = weUserMapper.selectOne(new LambdaQueryWrapperX<WeUserDO>().eq(WeUserDO::getSysUserId, getLoginUserId()), false);
        return BeanUtils.toBean(user, WeUserRespVO.class);
    }

    @Override
    public void unBindUser() {
        weUserMapper.update(new LambdaUpdateWrapper<WeUserDO>()
                .set(WeUserDO::getSysUserId, null)
                .eq(WeUserDO::getSysUserId, getLoginUserId())
        );
    }

    @Override
    public Long getUserIdByWeUserId(String weUserId) {
        WeUserDO user = weUserMapper.selectOne(WeUserDO::getWeUserId, weUserId);
        return Objects.nonNull(user) ? user.getSysUserId() : null;
    }

    @Override
    public Map<Long, WeUserDO> getWeUserBindStatus(List<Long> sysUserIdList) {
        if (CollUtil.isEmpty(sysUserIdList)) {
            return Collections.emptyMap();
        }
        List<WeUserDO> list = weUserMapper.selectList(
                new LambdaQueryWrapperX<WeUserDO>()
                        .in(WeUserDO::getSysUserId, sysUserIdList)
        );
        return CollectionUtils.convertMap(list, WeUserDO::getSysUserId);
    }

    @Override
    public Map<String, WeUserDO> getWeUserMap(List<String> weUserIdList) {
        if (CollUtil.isEmpty(weUserIdList)) {
            return Collections.emptyMap();
        }
        List<WeUserDO> list = weUserMapper.selectList(
                new LambdaQueryWrapperX<WeUserDO>()
                        .in(WeUserDO::getWeUserId, weUserIdList)
        );
        return CollectionUtils.convertMap(list, WeUserDO::getWeUserId);
    }

    @Override
    public List<WeUserDO> getWeUserList(String name) {
        return weUserMapper.selectList(
                new LambdaQueryWrapperX<WeUserDO>()
                        .eq(WeUserDO::getBindStatus, 1)
                        .likeIfPresent(WeUserDO::getNickname, name)
        );
    }

    /**
     * @param code
     * @return
     */
    @Override
    public String getUserIdByAuthCode(String code) {
        WeComProviderConfigDO providerConfig = providerConfigService.getProviderConfig();
        String accessToken = providerConfig.getSuiteAccessToken();

        if (StrUtil.isNotEmpty(accessToken)) {
            String body = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserinfo3rd?suite_access_token=" + accessToken + "&code=" + code);
            JSONObject userData = JSONUtil.parseObj(body);
            log.info("获取登录用户userid: {}", userData);
            String WxUserId = userData.getStr("userid");
            return WxUserId;
        }
        return null;
    }

    @Override
    public String getWeUserIdBySysUserId(Long loginUserId) {
        WeUserDO user = weUserMapper.selectOne(WeUserDO::getSysUserId, loginUserId);
        return Objects.isNull(user) ? null : user.getWeUserId();
    }

    /**
     * 企业微信部门同步逻辑
     * 1. 从api获取企业微信部门列表
     * 2. 从本地获取已创建的部门列表
     *
     * @return
     * @author PetePower
     * @since 2024-07-12
     */
    @Override
    public Boolean syncWeUser() {
        // 先校验api调用次数， 10分钟内只能调用一次
//        checkLockStatus();
//            log.info("同步部门：Begin -------------- ");
//            syncDept();
        log.info("同步用户：Begin -------------- ");
        syncUser();
        log.info("同步完成：Finish -------------- ");

        return true;
    }

    /**
     * 获取访问用户身份
     * 最后更新：2022/09/01
     * 请求方式：GET（HTTPS）
     * 请求地址：https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserinfo3rd?suite_access_token=SUITE_ACCESS_TOKEN&code=CODE
     *
     * @param state
     * @param code
     * @return
     * @author PetePower
     * @since 2024-07-15
     */
    @Override
    public Boolean bindWeUser(String state, String code) {
        // 解析获取UserId和TenantId
        List<String> stateList = StrUtil.split(state, "_");
        String UserId = stateList.get(0).replace("UserId:", "");
        String TenantId = stateList.get(1).replace("TenantId:", "");
        WeComProviderConfigDO providerConfig = providerConfigService.getProviderConfig();
        return TenantUtils.execute(Long.parseLong(TenantId), () -> {
            String accessToken = providerConfig.getLoginSuiteAccessToken();
            if (StrUtil.isNotEmpty(accessToken)) {
                String body = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserinfo3rd?suite_access_token=" + accessToken + "&code=" + code);
                JSONObject userData = JSONUtil.parseObj(body);
                String userTicket = userData.getStr("user_ticket");
                String wxUserId = userData.getStr("userid");
                String openUserId = userData.getStr("open_userid");
                String corpId = userData.getStr("corpid");
                log.debug("userData:{}", userData);
                // 查询用户
                AdminUserRespDTO user = adminUserApi.getUser(Long.parseLong(UserId));
                if (Objects.isNull(user)) {
                    throw exception(new ErrorCode(100500, "用户不存在"));
                }
                //查询对应企业信息
                WeComApiConfigDO apiConfig = apiConfigService.getWeComApiConfigByCorpId(corpId);
                if (Objects.isNull(apiConfig)) {
                    throw exception(new ErrorCode(100500, "您所在的企业未安装此应用，无法使用企微快捷登录"));
                }

                bindUser(wxUserId, openUserId, Long.parseLong(UserId));


//                if (StrUtil.isNotEmpty(UserTicket)) {
//                    // 使用UserTicket 去获取更新敏感信息
//                    String body2 = HttpUtil.createGet("https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserdetail3rd?suite_access_token=" + accessToken)
//                            .body(JSONUtil.toJsonStr(MapUtil.of("user_ticket", UserTicket)))
//                            .execute()
//                            .body();
//                    JSONObject userInfo = JSONUtil.parseObj(body2);
//                    log.info("get User Info ===== : {}", userInfo);
//
//                    weUserMapper.update((new LambdaUpdateWrapper<WeUserDO>()
//                            .eq(WeUserDO::getWeUserId, WxUserId)
//                            .set(WeUserDO::getNickname, userInfo.getStr("name"))
//                            .set(WeUserDO::getGender, userInfo.getInt("gender"))
//                            .set(WeUserDO::getAvatar, userInfo.getStr("avatar"))
//                            .set(WeUserDO::getQrCode, userInfo.getStr("qr_code"))
//                    ));
//                }

            }
            return true;

        });
    }

    /**
     * 网站扫码登录
     *
     * @param code 临时授权码
     * @return
     */
    @Override
    public OAuth2AccessTokenRespDTO weUserLogin(String code) {
        WeComProviderConfigDO providerConfig = providerConfigService.getProviderConfig();
        final String accessToken = providerConfig.getLoginSuiteAccessToken();
        JSONObject result = (new WeApi(accessToken)).weUserLogin(code);
        String corpId = result.getStr("corpid");
        String weUserId = result.getStr("userid");
        String openUserId = result.getStr("open_userid");
        log.info("获取到的授权信息： {}", result);
        if (StrUtil.isEmpty(corpId)) {
            throw exception(new ErrorCode(100500, "您所在的企业未安装此应用，无法使用企微快捷登录"));
        }

        return createAccessTokenRespDTO(corpId, weUserId, openUserId, false, null);
    }

    /**
     * 微信内登录
     */
    @Override
    public OAuth2AccessTokenRespDTO weUserLoginInner(String code) {
        WeComProviderConfigDO providerConfig = providerConfigService.getProviderConfig();
        log.info("providerConfig： {}", providerConfig);
        final String accessToken = providerConfig.getSuiteAccessToken();

//        String body = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserinfo3rd?debug=1&suite_access_token=" + accessToken + "&code=" + code);
//        JSONObject result = JSONUtil.parseObj(body);

        JSONObject result = (new WeApi(accessToken)).weUserLogin(code);
        String corpId = result.getStr("corpid");
        String weUserId = result.getStr("userid");
        String openUserId = result.getStr("open_userid");
        log.info("获取到的授权信息： {}", result);
        if (StrUtil.isEmpty(corpId)) {
            throw exception(new ErrorCode(100500, "您所在的企业未安装此应用，无法使用企微快捷登录"));
        }

        return createAccessTokenRespDTO(corpId, weUserId, openUserId, false, null);
    }

    @Override
    public OAuth2AccessTokenRespDTO weUserQuickLogin(WeComQuickLoginReqVo reqVo) {
        log.debug("weUserQuickLogin:{}", reqVo);
        log.debug("getLoginUserId:{}", getLoginUserId());
        if (!StrUtil.equals(stringRedisTemplate.opsForValue().get(USER_BIND_KEY + reqVo.getWeUserId()), reqVo.getWeToken())) {
            throw exception(new ErrorCode(100500, "token验证失败，请重新登录"));
        }
        return createAccessTokenRespDTO(reqVo.getCorpId(), reqVo.getWeUserId(), reqVo.getOpenUserId(), ObjUtil.isEmpty(reqVo.getSysUserId()), reqVo.getSysUserId());
    }

    /**
     * @param corpid
     * @param weUserId
     * @param openUserId
     * @param isBind     为true，为当前登录企微用户绑定系统用户
     * @param sysUserId  为空，则创建系统用户
     * @return
     */
    public OAuth2AccessTokenRespDTO createAccessTokenRespDTO(String corpid, String weUserId, String openUserId, boolean isBind, Long sysUserId) {
        // 1. 校验企业是否存在
        WeComApiConfigDO apiConfig = apiConfigService.getWeComApiConfigByCorpId(corpid);
        if (Objects.isNull(apiConfig)) {
            throw exception(new ErrorCode(100500, "您所在的企业未安装此应用，无法使用企微快捷登录"));
        }
        AtomicReference<Long> currentSysUserId = new AtomicReference<>(sysUserId);
        // 2. 企业存在， 查询用户
        // 2.1 userId 不存在，则新建用户， 继续
        AdminUserRespDTO user = TenantUtils.execute(apiConfig.getTenantId(), () -> {
            if (isBind) {
                return bindUser(weUserId, openUserId, currentSysUserId.get());
            } else {
                // 查找 WeUser, 看是否绑定了user
                WeUserDO userDO = weUserMapper.selectOne(WeUserDO::getWeUserId, weUserId);
                if (Objects.isNull(userDO)) {
                    return null;
                }
                log.debug("weUserDO:{}", userDO);
                return adminUserApi.getUser(userDO.getSysUserId());
            }

        });
        if (Objects.isNull(user)) {
//            throw exception(new ErrorCode(100500, "当前登录用户尚未创建或绑定CRM系统账号，请联系企业超管开通账号"));
            /**
             * 生成一个token防止被攻击
             */
            String weToken = RandomUtil.randomString(32);
            stringRedisTemplate.opsForValue().set(USER_BIND_KEY + weUserId, weToken, 10, TimeUnit.MINUTES);

            return new OAuth2AccessTokenRespDTO().setCorpId(corpid).setWeUserId(weUserId).setOpenUserId(openUserId).setWeToken(weToken);
        }
        return TenantUtils.execute(apiConfig.getTenantId(), () -> oAuth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
                        .setTenantId(apiConfig.getTenantId())
                        .setUserType(UserTypeEnum.ADMIN.getValue()).setUserId(user.getId()).setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT)))
                .setSign(tenantApi.getTenantSign(apiConfig.getTenantId()));
    }

    @Override
    public AdminUserRespDTO bindUser(String weUserId, String openUserId, Long sysUserId) {

        WeUserDO weUserDO = weUserMapper.selectOne(WeUserDO::getWeUserId, weUserId);
        if (Objects.isNull(weUserDO)) {
            //企微用户信息不存在直接新增
            weUserDO = new WeUserDO();
            weUserDO.setWeUserId(weUserId).setWeOpenUserId(openUserId).setNickname(weUserId).setBindStatus(0);
            weUserMapper.insert(weUserDO);
        }
        if (ObjUtil.isEmpty(sysUserId)) {
            AdminUserSaveReqDTO createReqDTO = new AdminUserSaveReqDTO();
            String nickName = StrUtil.sub(weUserId, 0, 30);
            createReqDTO.setNickname(nickName);
            createReqDTO.setUsername(nickName);
            createReqDTO.setPassword(configApi.getConfigValueByKey("sys.user.init-password"));
            sysUserId = adminUserApi.createUser(createReqDTO, false);
        }
        AdminUserRespDTO userRespDTO = adminUserApi.getUser(sysUserId);
        if (ObjUtil.isEmpty(userRespDTO)) {
            //这里做个判断,当前企业下查询不到用户，表示企微关联的企业不一致
            throw exception(new ErrorCode(100500, "当前登录用户所在企业与企业微信关联企业不符"));
        }
        weUserMapper.update((new LambdaUpdateWrapper<WeUserDO>()
                .eq(WeUserDO::getWeOpenUserId, openUserId)
                .set(WeUserDO::getSysUserId, sysUserId)
                .set(WeUserDO::getWeUserId, weUserId)
                .set(WeUserDO::getBindStatus, 1)
                .set(WeUserDO::getNickname, userRespDTO.getNickname())
        ));


        return adminUserApi.getUser(sysUserId);
    }


    @Override
    public String getAuthUrl(Long tenantId, Long userId) {
        String state = StrUtil.concat(true, "UserId:" + userId, "_TenantId:" + tenantId);
        /**
         * https://open.weixin.qq.com/connect/oauth2/authorize?
         * appid=CORPID
         * &redirect_uri=REDIRECT_URI
         * &response_type=code
         * &scope=snsapi_privateinfo
         * &agentid=AGENTID
         * &state=STATE#wechat_redirect
         *
         * 网页授权登录URL
         * https://login.work.weixin.qq.com/wwlogin/sso/login?login_type=LOGIN_TYPE&appid=APPID&redirect_uri=REDIRECT_URI&state=STATE
         */
        WeComProviderConfigDO apiConfig = providerConfigService.getProviderConfig();
        String corpId = apiConfig.getLoginSuiteId();
        if (!StrUtil.isAllNotEmpty(corpId)) {
            throw exception(API_CONFIG_NOT_EXISTS);
        }
        Map<String, String> params = new HashMap<>();
        params.put("appid", corpId);
        params.put("redirect_uri", URLUtil.encode(USER_AUTH_REDIRECT_URL));
        params.put("login_type", "ServiceApp");
        params.put("state", state);
//        params.put("agentid", agentId);
        return StrUtil.concat(true, "https://login.work.weixin.qq.com/wwlogin/sso/login?", HttpUtil.toParams(params, CharsetUtil.CHARSET_UTF_8, true));
    }

    private void syncUser() {
        // 获取userId
        WeComApiConfigDO apiConfig = apiConfigService.getWeComApiConfig();
        if (StrUtil.isEmpty(apiConfig.getContactAccessToken())) {
            throw exception(API_NO_ACCESS_TOKEN);
        }
        List<String> openUserList = new ArrayList<>();

        exec(apiConfig.getContactAccessToken(), null, openUserList);

        // 同步完之后， 获取本地的员工列表， 并和企业微信的员工列表比对， 如果有多余的本地数据，则删除本地数据
        List<WeUserDO> weUserDOList = weUserMapper.selectList();
        List<Long> deleteList = new ArrayList<>();
        for (WeUserDO weUserDO : weUserDOList) {
            boolean has = false;
            for (String s : openUserList) {
                if (ObjectUtil.equal(weUserDO.getWeOpenUserId(), s)) {
                    has = true;
                    break;
                }
            }
            if (!has) {
                deleteList.add(weUserDO.getId());
            }
        }
        if (CollUtil.isNotEmpty(deleteList)) {
            weUserMapper.deleteBatchIds(deleteList);
        }
    }

    public void exec(String accessToken, String cursor, List<String> list) {
        Map<String, Object> params = new HashMap<>();
        params.put("limit", 1000);
        if (StrUtil.isNotEmpty(cursor)) {
            params.put("cursor", cursor);
        }
        WeApi weApi = new WeApi(accessToken).body(params);
        JSONObject jsonObject = weApi.getUserList();
        JSONArray jsonArray = jsonObject.getJSONArray("dept_user");
        String nextCursor = jsonObject.getStr("next_cursor");
        jsonArray.forEach(userDept -> {
            // 从库里面查找
            String openUserId = JSONUtil.parseObj(userDept).getStr("open_userid");
            list.add(openUserId);
            Long DeptId = JSONUtil.parseObj(userDept).getLong("department");
            try {
                WeUserDO weUserDO = weUserMapper.selectOne(WeUserDO::getWeOpenUserId, openUserId);
                if (Objects.isNull(weUserDO)) {
                    // 新的数据，直接mapping 一下然后入库
                    weUserDO = wxUserToWeUser(openUserId, DeptId);
                    weUserMapper.insert(weUserDO);
                } else {
                    // 需要更新
                    weUserDO.setWeOpenUserId(openUserId);
                    weUserDO.setDeptId("," + DeptId + ",");
                    weUserMapper.updateById(weUserDO);
                }
            } catch (Exception e) {
                throw exception(SYNC_ERROR_500);
            }
        });
        if (StrUtil.isNotEmpty(nextCursor)) {
            exec(accessToken, nextCursor, list);
        }
    }

    private WeUserDO wxUserToWeUser(String userId, Long deptId) {
        WeUserDO user = new WeUserDO();
        user.setWeOpenUserId(userId);
        user.setNickname("未绑定员工");
        user.setWeUserId(userId);
        user.setDeptId("," + deptId + ",");
        user.setBindStatus(0);
        return user;
    }

    /**
     * 校验api调用次数， 10分钟内只能调用一次
     *
     * @author PetePower
     * @since 2024-07-12
     */
    private void checkLockStatus() {
        String lock = stringRedisTemplate.opsForValue().get(LOCK_KEY + TenantContextHolder.getTenantIdStr());
        if (StrUtil.isEmpty(lock)) {
            stringRedisTemplate.opsForValue().set(
                    LOCK_KEY + TenantContextHolder.getTenantIdStr(),
                    "LOCK",
                    1,
                    TimeUnit.MINUTES
            );
        } else {
            throw exception(SYNC_ERROR_API_LIMIT);
        }
    }

    /**
     * 同步部门数据
     *
     * @throws WxErrorException
     * @author PetePower
     * @since 2024-07-12
     */
//    private void syncDept() throws WxErrorException {
//        List<WxCpDepart> list = cpServiceFactory.getDepartmentService().list(null);
//        if (CollUtil.isEmpty(list)) {
//            return;
//        }
//        // 改成： 直接删除本地的吧。 因为user::dept_id 使用的是企业微信的原生id， 那么删除本地的数据id也是没事的
//        weDeptMapper.delete(new LambdaQueryWrapperX<>());
//        List<WeDeptDO> insertList = new ArrayList<>();
//        list.forEach(wxDept -> {
//            WeDeptDO weDeptDO = new WeDeptDO();
//            weDeptDO.setWeDeptId(wxDept.getId());
////            if (Objects.nonNull(wxDept.getParentId())) {
////                list.stream().filter(v -> {
////                    return ObjectUtil.equal(v.getId(), wxDept.getParentId());
////                }).findFirst().ifPresent(p -> {
////                    weDeptDO.setParentId(p.getId());
////                });
////            }
//            weDeptDO.setParentId(wxDept.getParentId());
//            weDeptDO.setWeDeptName(wxDept.getName());
//            weDeptDO.setWeDeptLeader(ArrayUtil.join(wxDept.getDepartmentLeader(), ","));
//            weDeptDO.setSort(wxDept.getOrder().intValue());
//            insertList.add(weDeptDO);
//        });
//        if (CollUtil.isNotEmpty(insertList)) {
//            weDeptMapper.insertBatch(insertList);
//        }
//    }
}